home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 13 The Compute Shader / SobelFilter / SobelApp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  49.8 KB  |  1,385 lines

  1. //***************************************************************************************
  2. // SobelApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "../../Common/d3dApp.h"
  6. #include "../../Common/MathHelper.h"
  7. #include "../../Common/UploadBuffer.h"
  8. #include "../../Common/GeometryGenerator.h"
  9. #include "FrameResource.h"
  10. #include "GpuWaves.h"
  11. #include "SobelFilter.h"
  12. #include "RenderTarget.h"
  13.  
  14. using Microsoft::WRL::ComPtr;
  15. using namespace DirectX;
  16. using namespace DirectX::PackedVector;
  17.  
  18. #pragma comment(lib, "d3dcompiler.lib")
  19. #pragma comment(lib, "D3D12.lib")
  20.  
  21. const int gNumFrameResources = 3;
  22.  
  23. // Lightweight structure stores parameters to draw a shape.  This will
  24. // vary from app-to-app.
  25. struct RenderItem
  26. {
  27.     RenderItem() = default;
  28.  
  29.     // World matrix of the shape that describes the object's local space
  30.     // relative to the world space, which defines the position, orientation,
  31.     // and scale of the object in the world.
  32.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  33.  
  34.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  35.  
  36.     // Used for GPU waves render items.
  37.     DirectX::XMFLOAT2 DisplacementMapTexelSize = { 1.0f, 1.0f };
  38.     float GridSpatialStep = 1.0f;
  39.  
  40.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  41.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  42.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  43.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  44.     int NumFramesDirty = gNumFrameResources;
  45.  
  46.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  47.     UINT ObjCBIndex = -1;
  48.  
  49.     Material* Mat = nullptr;
  50.     MeshGeometry* Geo = nullptr;
  51.  
  52.     // Primitive topology.
  53.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  54.  
  55.     // DrawIndexedInstanced parameters.
  56.     UINT IndexCount = 0;
  57.     UINT StartIndexLocation = 0;
  58.     int BaseVertexLocation = 0;
  59. };
  60.  
  61. enum class RenderLayer : int
  62. {
  63.     Opaque = 0,
  64.     Transparent,
  65.     AlphaTested,
  66.     GpuWaves,
  67.     Count
  68. };
  69.  
  70. class SobelApp : public D3DApp
  71. {
  72. public:
  73.     SobelApp(HINSTANCE hInstance);
  74.     SobelApp(const SobelApp& rhs) = delete;
  75.     SobelApp& operator=(const SobelApp& rhs) = delete;
  76.     ~SobelApp();
  77.  
  78.     virtual bool Initialize()override;
  79.  
  80. private:
  81.     virtual void CreateRtvAndDsvDescriptorHeaps()override;
  82.     virtual void OnResize()override;
  83.     virtual void Update(const GameTimer& gt)override;
  84.     virtual void Draw(const GameTimer& gt)override;
  85.  
  86.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  87.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  88.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  89.  
  90.     void OnKeyboardInput(const GameTimer& gt);
  91.     void UpdateCamera(const GameTimer& gt);
  92.     void AnimateMaterials(const GameTimer& gt);
  93.     void UpdateObjectCBs(const GameTimer& gt);
  94.     void UpdateMaterialCBs(const GameTimer& gt);
  95.     void UpdateMainPassCB(const GameTimer& gt);
  96.     void UpdateWavesGPU(const GameTimer& gt);
  97.  
  98.     void LoadTextures();
  99.     void BuildRootSignature();
  100.     void BuildWavesRootSignature();
  101.     void BuildPostProcessRootSignature();
  102.     void BuildDescriptorHeaps();
  103.     void BuildShadersAndInputLayout();
  104.     void BuildLandGeometry();
  105.     void BuildWavesGeometry();
  106.     void BuildBoxGeometry();
  107.     void BuildPSOs();
  108.     void BuildFrameResources();
  109.     void BuildMaterials();
  110.     void BuildRenderItems();
  111.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  112.     void DrawFullscreenQuad(ID3D12GraphicsCommandList* cmdList);
  113.  
  114.     std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
  115.  
  116.     float GetHillsHeight(float x, float z)const;
  117.     XMFLOAT3 GetHillsNormal(float x, float z)const;
  118.  
  119. private:
  120.  
  121.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  122.     FrameResource* mCurrFrameResource = nullptr;
  123.     int mCurrFrameResourceIndex = 0;
  124.  
  125.     UINT mCbvSrvDescriptorSize = 0;
  126.  
  127.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  128.     ComPtr<ID3D12RootSignature> mWavesRootSignature = nullptr;
  129.     ComPtr<ID3D12RootSignature> mPostProcessRootSignature = nullptr;
  130.  
  131.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  132.  
  133.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  134.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  135.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  136.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  137.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  138.  
  139.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  140.  
  141.     // List of all the render items.
  142.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  143.  
  144.     // Render items divided by PSO.
  145.     std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
  146.  
  147.     std::unique_ptr<GpuWaves> mWaves;
  148.  
  149.     std::unique_ptr<RenderTarget> mOffscreenRT = nullptr;
  150.  
  151.     std::unique_ptr<SobelFilter> mSobelFilter = nullptr;
  152.  
  153.     PassConstants mMainPassCB;
  154.  
  155.     XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
  156.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  157.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  158.  
  159.     float mTheta = 1.5f*XM_PI;
  160.     float mPhi = XM_PIDIV2 - 0.1f;
  161.     float mRadius = 50.0f;
  162.  
  163.     POINT mLastMousePos;
  164. };
  165.  
  166. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  167.     PSTR cmdLine, int showCmd)
  168. {
  169.     // Enable run-time memory check for debug builds.
  170. #if defined(DEBUG) | defined(_DEBUG)
  171.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  172. #endif
  173.  
  174.     try
  175.     {
  176.         SobelApp theApp(hInstance);
  177.         if(!theApp.Initialize())
  178.             return 0;
  179.  
  180.         return theApp.Run();
  181.     }
  182.     catch(DxException& e)
  183.     {
  184.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  185.         return 0;
  186.     }
  187. }
  188.  
  189. SobelApp::SobelApp(HINSTANCE hInstance)
  190.     : D3DApp(hInstance)
  191. {
  192. }
  193.  
  194. SobelApp::~SobelApp()
  195. {
  196.     if(md3dDevice != nullptr)
  197.         FlushCommandQueue();
  198. }
  199.  
  200. bool SobelApp::Initialize()
  201. {
  202.     if(!D3DApp::Initialize())
  203.         return false;
  204.  
  205.     // Reset the command list to prep for initialization commands.
  206.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  207.  
  208.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  209.     // so we have to query this information.
  210.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  211.  
  212.     mWaves = std::make_unique<GpuWaves>(
  213.         md3dDevice.Get(), 
  214.         mCommandList.Get(),
  215.         256, 256, 0.25f, 0.03f, 2.0f, 0.2f);
  216.  
  217.     mSobelFilter = std::make_unique<SobelFilter>(
  218.         md3dDevice.Get(),
  219.         mClientWidth, mClientHeight,
  220.         mBackBufferFormat);
  221.  
  222.     mOffscreenRT = std::make_unique<RenderTarget>(
  223.         md3dDevice.Get(),
  224.         mClientWidth, mClientHeight,
  225.         mBackBufferFormat);
  226.  
  227.     LoadTextures();
  228.     BuildRootSignature();
  229.     BuildWavesRootSignature();
  230.     BuildPostProcessRootSignature();
  231.     BuildDescriptorHeaps();
  232.     BuildShadersAndInputLayout();
  233.     BuildLandGeometry();
  234.     BuildWavesGeometry();
  235.     BuildBoxGeometry();
  236.     BuildMaterials();
  237.     BuildRenderItems();
  238.     BuildFrameResources();
  239.     BuildPSOs();
  240.  
  241.     // Execute the initialization commands.
  242.     ThrowIfFailed(mCommandList->Close());
  243.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  244.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  245.  
  246.     // Wait until initialization is complete.
  247.     FlushCommandQueue();
  248.  
  249.     return true;
  250. }
  251.  
  252. void SobelApp::CreateRtvAndDsvDescriptorHeaps()
  253. {
  254.     // Add +1 descriptor for offscreen render target.
  255.     D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc;
  256.     rtvHeapDesc.NumDescriptors = SwapChainBufferCount + 1;
  257.     rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
  258.     rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
  259.     rtvHeapDesc.NodeMask = 0;
  260.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(
  261.         &rtvHeapDesc, IID_PPV_ARGS(mRtvHeap.GetAddressOf())));
  262.  
  263.     D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc;
  264.     dsvHeapDesc.NumDescriptors = 1;
  265.     dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
  266.     dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
  267.     dsvHeapDesc.NodeMask = 0;
  268.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(
  269.         &dsvHeapDesc, IID_PPV_ARGS(mDsvHeap.GetAddressOf())));
  270. }
  271.  
  272. void SobelApp::OnResize()
  273. {
  274.     D3DApp::OnResize();
  275.  
  276.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  277.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  278.     XMStoreFloat4x4(&mProj, P);
  279.  
  280.     if(mSobelFilter != nullptr)
  281.     {
  282.         mSobelFilter->OnResize(mClientWidth, mClientHeight);
  283.     }
  284.  
  285.     if(mOffscreenRT != nullptr)
  286.     {
  287.         mOffscreenRT->OnResize(mClientWidth, mClientHeight);
  288.     }
  289. }
  290.  
  291. void SobelApp::Update(const GameTimer& gt)
  292. {
  293.     OnKeyboardInput(gt);
  294.     UpdateCamera(gt);
  295.  
  296.     // Cycle through the circular frame resource array.
  297.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  298.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  299.  
  300.     // Has the GPU finished processing the commands of the current frame resource?
  301.     // If not, wait until the GPU has completed commands up to this fence point.
  302.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  303.     {
  304.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  305.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  306.         WaitForSingleObject(eventHandle, INFINITE);
  307.         CloseHandle(eventHandle);
  308.     }
  309.  
  310.     AnimateMaterials(gt);
  311.     UpdateObjectCBs(gt);
  312.     UpdateMaterialCBs(gt);
  313.     UpdateMainPassCB(gt);
  314. }
  315.  
  316. void SobelApp::Draw(const GameTimer& gt)
  317. {
  318.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  319.  
  320.     // Reuse the memory associated with command recording.
  321.     // We can only reset when the associated command lists have finished execution on the GPU.
  322.     ThrowIfFailed(cmdListAlloc->Reset());
  323.  
  324.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  325.     // Reusing the command list reuses memory.
  326.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  327.  
  328.     ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
  329.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  330.  
  331.     UpdateWavesGPU(gt);
  332.  
  333.     mCommandList->SetPipelineState(mPSOs["opaque"].Get());
  334.  
  335.     mCommandList->RSSetViewports(1, &mScreenViewport);
  336.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  337.  
  338.     // Change offscreen texture to be used as a a render target output.
  339.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mOffscreenRT->Resource(),
  340.         D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET));
  341.  
  342.     // Clear the back buffer and depth buffer.
  343.     mCommandList->ClearRenderTargetView(mOffscreenRT->Rtv(), (float*)&mMainPassCB.FogColor, 0, nullptr);
  344.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  345.  
  346.     // Specify the buffers we are going to render to.
  347.     mCommandList->OMSetRenderTargets(1, &mOffscreenRT->Rtv(), true, &DepthStencilView());
  348.  
  349.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  350.  
  351.     auto passCB = mCurrFrameResource->PassCB->Resource();
  352.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  353.  
  354.     mCommandList->SetGraphicsRootDescriptorTable(4, mWaves->DisplacementMap());
  355.  
  356.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
  357.  
  358.     mCommandList->SetPipelineState(mPSOs["alphaTested"].Get());
  359.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::AlphaTested]);
  360.  
  361.     mCommandList->SetPipelineState(mPSOs["transparent"].Get());
  362.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Transparent]);
  363.  
  364.     mCommandList->SetPipelineState(mPSOs["wavesRender"].Get());
  365.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::GpuWaves]);
  366.  
  367.     // Change offscreen texture to be used as an input.
  368.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mOffscreenRT->Resource(),
  369.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));
  370.  
  371.     mSobelFilter->Execute(mCommandList.Get(), mPostProcessRootSignature.Get(), 
  372.         mPSOs["sobel"].Get(), mOffscreenRT->Srv());
  373.  
  374.     //
  375.     // Switching back to back buffer rendering.
  376.     //
  377.  
  378.     // Indicate a state transition on the resource usage.
  379.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  380.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  381.  
  382.     // Specify the buffers we are going to render to.
  383.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  384.  
  385.     mCommandList->SetGraphicsRootSignature(mPostProcessRootSignature.Get());
  386.     mCommandList->SetPipelineState(mPSOs["composite"].Get());
  387.     mCommandList->SetGraphicsRootDescriptorTable(0, mOffscreenRT->Srv());
  388.     mCommandList->SetGraphicsRootDescriptorTable(1, mSobelFilter->OutputSrv());
  389.     DrawFullscreenQuad(mCommandList.Get());
  390.  
  391.     // Indicate a state transition on the resource usage.
  392.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  393.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  394.  
  395.     // Done recording commands.
  396.     ThrowIfFailed(mCommandList->Close());
  397.  
  398.     // Add the command list to the queue for execution.
  399.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  400.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  401.  
  402.     // Swap the back and front buffers
  403.     ThrowIfFailed(mSwapChain->Present(0, 0));
  404.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  405.  
  406.     // Advance the fence value to mark commands up to this fence point.
  407.     mCurrFrameResource->Fence = ++mCurrentFence;
  408.  
  409.     // Add an instruction to the command queue to set a new fence point. 
  410.     // Because we are on the GPU timeline, the new fence point won't be 
  411.     // set until the GPU finishes processing all the commands prior to this Signal().
  412.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  413. }
  414.  
  415. void SobelApp::OnMouseDown(WPARAM btnState, int x, int y)
  416. {
  417.     mLastMousePos.x = x;
  418.     mLastMousePos.y = y;
  419.  
  420.     SetCapture(mhMainWnd);
  421. }
  422.  
  423. void SobelApp::OnMouseUp(WPARAM btnState, int x, int y)
  424. {
  425.     ReleaseCapture();
  426. }
  427.  
  428. void SobelApp::OnMouseMove(WPARAM btnState, int x, int y)
  429. {
  430.     if((btnState & MK_LBUTTON) != 0)
  431.     {
  432.         // Make each pixel correspond to a quarter of a degree.
  433.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  434.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  435.  
  436.         // Update angles based on input to orbit camera around box.
  437.         mTheta += dx;
  438.         mPhi += dy;
  439.  
  440.         // Restrict the angle mPhi.
  441.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  442.     }
  443.     else if((btnState & MK_RBUTTON) != 0)
  444.     {
  445.         // Make each pixel correspond to 0.2 unit in the scene.
  446.         float dx = 0.2f*static_cast<float>(x - mLastMousePos.x);
  447.         float dy = 0.2f*static_cast<float>(y - mLastMousePos.y);
  448.  
  449.         // Update the camera radius based on input.
  450.         mRadius += dx - dy;
  451.  
  452.         // Restrict the radius.
  453.         mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
  454.     }
  455.  
  456.     mLastMousePos.x = x;
  457.     mLastMousePos.y = y;
  458. }
  459.  
  460. void SobelApp::OnKeyboardInput(const GameTimer& gt)
  461. {
  462. }
  463.  
  464. void SobelApp::UpdateCamera(const GameTimer& gt)
  465. {
  466.     // Convert Spherical to Cartesian coordinates.
  467.     mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
  468.     mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
  469.     mEyePos.y = mRadius*cosf(mPhi);
  470.  
  471.     // Build the view matrix.
  472.     XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
  473.     XMVECTOR target = XMVectorZero();
  474.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  475.  
  476.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  477.     XMStoreFloat4x4(&mView, view);
  478. }
  479.  
  480. void SobelApp::AnimateMaterials(const GameTimer& gt)
  481. {
  482.     // Scroll the water material texture coordinates.
  483.     auto waterMat = mMaterials["water"].get();
  484.  
  485.     float& tu = waterMat->MatTransform(3, 0);
  486.     float& tv = waterMat->MatTransform(3, 1);
  487.  
  488.     tu += 0.1f * gt.DeltaTime();
  489.     tv += 0.02f * gt.DeltaTime();
  490.  
  491.     if(tu >= 1.0f)
  492.         tu -= 1.0f;
  493.  
  494.     if(tv >= 1.0f)
  495.         tv -= 1.0f;
  496.  
  497.     waterMat->MatTransform(3, 0) = tu;
  498.     waterMat->MatTransform(3, 1) = tv;
  499.  
  500.     // Material has changed, so need to update cbuffer.
  501.     waterMat->NumFramesDirty = gNumFrameResources;
  502. }
  503.  
  504. void SobelApp::UpdateObjectCBs(const GameTimer& gt)
  505. {
  506.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  507.     for(auto& e : mAllRitems)
  508.     {
  509.         // Only update the cbuffer data if the constants have changed.  
  510.         // This needs to be tracked per frame resource.
  511.         if(e->NumFramesDirty > 0)
  512.         {
  513.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  514.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  515.  
  516.             ObjectConstants objConstants;
  517.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  518.             XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
  519.             objConstants.DisplacementMapTexelSize = e->DisplacementMapTexelSize;
  520.             objConstants.GridSpatialStep = e->GridSpatialStep;
  521.  
  522.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  523.  
  524.             // Next FrameResource need to be updated too.
  525.             e->NumFramesDirty--;
  526.         }
  527.     }
  528. }
  529.  
  530. void SobelApp::UpdateMaterialCBs(const GameTimer& gt)
  531. {
  532.     auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
  533.     for(auto& e : mMaterials)
  534.     {
  535.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  536.         // data changes, it needs to be updated for each FrameResource.
  537.         Material* mat = e.second.get();
  538.         if(mat->NumFramesDirty > 0)
  539.         {
  540.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  541.  
  542.             MaterialConstants matConstants;
  543.             matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
  544.             matConstants.FresnelR0 = mat->FresnelR0;
  545.             matConstants.Roughness = mat->Roughness;
  546.             XMStoreFloat4x4(&matConstants.MatTransform, XMMatrixTranspose(matTransform));
  547.  
  548.             currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
  549.  
  550.             // Next FrameResource need to be updated too.
  551.             mat->NumFramesDirty--;
  552.         }
  553.     }
  554. }
  555.  
  556. void SobelApp::UpdateMainPassCB(const GameTimer& gt)
  557. {
  558.     XMMATRIX view = XMLoadFloat4x4(&mView);
  559.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  560.  
  561.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  562.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  563.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  564.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  565.  
  566.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  567.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  568.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  569.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  570.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  571.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  572.     mMainPassCB.EyePosW = mEyePos;
  573.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  574.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  575.     mMainPassCB.NearZ = 1.0f;
  576.     mMainPassCB.FarZ = 1000.0f;
  577.     mMainPassCB.TotalTime = gt.TotalTime();
  578.     mMainPassCB.DeltaTime = gt.DeltaTime();
  579.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  580.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  581.     mMainPassCB.Lights[0].Strength = { 0.6f, 0.6f, 0.6f };
  582.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  583.     mMainPassCB.Lights[1].Strength = { 0.3f, 0.3f, 0.3f };
  584.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  585.     mMainPassCB.Lights[2].Strength = { 0.15f, 0.15f, 0.15f };
  586.  
  587.     auto currPassCB = mCurrFrameResource->PassCB.get();
  588.     currPassCB->CopyData(0, mMainPassCB);
  589. }
  590.  
  591. void SobelApp::UpdateWavesGPU(const GameTimer& gt)
  592. {
  593.     // Every quarter second, generate a random wave.
  594.     static float t_base = 0.0f;
  595.     if((mTimer.TotalTime() - t_base) >= 0.25f)
  596.     {
  597.         t_base += 0.25f;
  598.  
  599.         int i = MathHelper::Rand(4, mWaves->RowCount() - 5);
  600.         int j = MathHelper::Rand(4, mWaves->ColumnCount() - 5);
  601.  
  602.         float r = MathHelper::RandF(1.0f, 2.0f);
  603.  
  604.         mWaves->Disturb(mCommandList.Get(), mWavesRootSignature.Get(), mPSOs["wavesDisturb"].Get(), i, j, r);
  605.     }
  606.  
  607.     // Update the wave simulation.
  608.     mWaves->Update(gt, mCommandList.Get(), mWavesRootSignature.Get(), mPSOs["wavesUpdate"].Get());
  609. }
  610.  
  611. void SobelApp::LoadTextures()
  612. {
  613.     auto grassTex = std::make_unique<Texture>();
  614.     grassTex->Name = "grassTex";
  615.     grassTex->Filename = L"../../Textures/grass.dds";
  616.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  617.         mCommandList.Get(), grassTex->Filename.c_str(),
  618.         grassTex->Resource, grassTex->UploadHeap));
  619.  
  620.     auto waterTex = std::make_unique<Texture>();
  621.     waterTex->Name = "waterTex";
  622.     waterTex->Filename = L"../../Textures/water1.dds";
  623.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  624.         mCommandList.Get(), waterTex->Filename.c_str(),
  625.         waterTex->Resource, waterTex->UploadHeap));
  626.  
  627.     auto fenceTex = std::make_unique<Texture>();
  628.     fenceTex->Name = "fenceTex";
  629.     fenceTex->Filename = L"../../Textures/WireFence.dds";
  630.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  631.         mCommandList.Get(), fenceTex->Filename.c_str(),
  632.         fenceTex->Resource, fenceTex->UploadHeap));
  633.  
  634.     mTextures[grassTex->Name] = std::move(grassTex);
  635.     mTextures[waterTex->Name] = std::move(waterTex);
  636.     mTextures[fenceTex->Name] = std::move(fenceTex);
  637. }
  638.  
  639. void SobelApp::BuildRootSignature()
  640. {
  641.     CD3DX12_DESCRIPTOR_RANGE texTable;
  642.     texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
  643.  
  644.     CD3DX12_DESCRIPTOR_RANGE displacementMapTable;
  645.     displacementMapTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);
  646.  
  647.     // Root parameter can be a table, root descriptor or root constants.
  648.     CD3DX12_ROOT_PARAMETER slotRootParameter[5];
  649.  
  650.     // Perfomance TIP: Order from most frequent to least frequent.
  651.     slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_ALL);
  652.     slotRootParameter[1].InitAsConstantBufferView(0);
  653.     slotRootParameter[2].InitAsConstantBufferView(1);
  654.     slotRootParameter[3].InitAsConstantBufferView(2);
  655.     slotRootParameter[4].InitAsDescriptorTable(1, &displacementMapTable, D3D12_SHADER_VISIBILITY_ALL);
  656.  
  657.     auto staticSamplers = GetStaticSamplers();
  658.  
  659.     // A root signature is an array of root parameters.
  660.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(5, slotRootParameter,
  661.         (UINT)staticSamplers.size(), staticSamplers.data(),
  662.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  663.  
  664.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  665.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  666.     ComPtr<ID3DBlob> errorBlob = nullptr;
  667.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  668.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  669.  
  670.     if(errorBlob != nullptr)
  671.     {
  672.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  673.     }
  674.     ThrowIfFailed(hr);
  675.  
  676.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  677.         0,
  678.         serializedRootSig->GetBufferPointer(),
  679.         serializedRootSig->GetBufferSize(),
  680.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  681. }
  682.  
  683. void SobelApp::BuildWavesRootSignature()
  684. {
  685.     CD3DX12_DESCRIPTOR_RANGE uavTable0;
  686.     uavTable0.Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0);
  687.  
  688.     CD3DX12_DESCRIPTOR_RANGE uavTable1;
  689.     uavTable1.Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 1);
  690.  
  691.     CD3DX12_DESCRIPTOR_RANGE uavTable2;
  692.     uavTable2.Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 2);
  693.  
  694.     // Root parameter can be a table, root descriptor or root constants.
  695.     CD3DX12_ROOT_PARAMETER slotRootParameter[4];
  696.  
  697.     // Perfomance TIP: Order from most frequent to least frequent.
  698.     slotRootParameter[0].InitAsConstants(6, 0);
  699.     slotRootParameter[1].InitAsDescriptorTable(1, &uavTable0);
  700.     slotRootParameter[2].InitAsDescriptorTable(1, &uavTable1);
  701.     slotRootParameter[3].InitAsDescriptorTable(1, &uavTable2);
  702.  
  703.     // A root signature is an array of root parameters.
  704.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
  705.         0, nullptr,
  706.         D3D12_ROOT_SIGNATURE_FLAG_NONE);
  707.  
  708.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  709.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  710.     ComPtr<ID3DBlob> errorBlob = nullptr;
  711.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  712.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  713.  
  714.     if(errorBlob != nullptr)
  715.     {
  716.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  717.     }
  718.     ThrowIfFailed(hr);
  719.  
  720.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  721.         0,
  722.         serializedRootSig->GetBufferPointer(),
  723.         serializedRootSig->GetBufferSize(),
  724.         IID_PPV_ARGS(mWavesRootSignature.GetAddressOf())));
  725. }
  726.  
  727. void SobelApp::BuildPostProcessRootSignature()
  728. {
  729.     CD3DX12_DESCRIPTOR_RANGE srvTable0;
  730.     srvTable0.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
  731.  
  732.     CD3DX12_DESCRIPTOR_RANGE srvTable1;
  733.     srvTable1.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);
  734.  
  735.     CD3DX12_DESCRIPTOR_RANGE uavTable0;
  736.     uavTable0.Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0);
  737.  
  738.     // Root parameter can be a table, root descriptor or root constants.
  739.     CD3DX12_ROOT_PARAMETER slotRootParameter[3];
  740.  
  741.     // Perfomance TIP: Order from most frequent to least frequent.
  742.     slotRootParameter[0].InitAsDescriptorTable(1, &srvTable0);
  743.     slotRootParameter[1].InitAsDescriptorTable(1, &srvTable1);
  744.     slotRootParameter[2].InitAsDescriptorTable(1, &uavTable0);
  745.  
  746.     auto staticSamplers = GetStaticSamplers();
  747.  
  748.     // A root signature is an array of root parameters.
  749.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(3, slotRootParameter,
  750.         (UINT)staticSamplers.size(), staticSamplers.data(),
  751.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  752.  
  753.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  754.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  755.     ComPtr<ID3DBlob> errorBlob = nullptr;
  756.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  757.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  758.  
  759.     if(errorBlob != nullptr)
  760.     {
  761.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  762.     }
  763.     ThrowIfFailed(hr);
  764.  
  765.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  766.         0,
  767.         serializedRootSig->GetBufferPointer(),
  768.         serializedRootSig->GetBufferSize(),
  769.         IID_PPV_ARGS(mPostProcessRootSignature.GetAddressOf())));
  770. }
  771.  
  772. void SobelApp::BuildDescriptorHeaps()
  773. {
  774.     // Offscreen RTV goes after the swap chain descriptors.
  775.     int rtvOffset = SwapChainBufferCount;
  776.  
  777.     UINT srvCount = 3;
  778.  
  779.     int waveSrvOffset = srvCount;
  780.     int sobelSrvOffset = waveSrvOffset + mWaves->DescriptorCount();
  781.     int offscreenSrvOffset = sobelSrvOffset + mSobelFilter->DescriptorCount();
  782.  
  783.     //
  784.     // Create the SRV heap.
  785.     //
  786.     D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  787.     srvHeapDesc.NumDescriptors =
  788.         srvCount +
  789.         mWaves->DescriptorCount() +
  790.         mSobelFilter->DescriptorCount() +
  791.         1; // extra offscreen render target
  792.     srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  793.     srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  794.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
  795.  
  796.     //
  797.     // Fill out the heap with actual descriptors.  
  798.     //
  799.     CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
  800.  
  801.     auto grassTex = mTextures["grassTex"]->Resource;
  802.     auto waterTex = mTextures["waterTex"]->Resource;
  803.     auto fenceTex = mTextures["fenceTex"]->Resource;
  804.  
  805.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  806.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  807.     srvDesc.Format = grassTex->GetDesc().Format;
  808.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  809.     srvDesc.Texture2D.MostDetailedMip = 0;
  810.     srvDesc.Texture2D.MipLevels = -1;
  811.     md3dDevice->CreateShaderResourceView(grassTex.Get(), &srvDesc, hDescriptor);
  812.  
  813.     // next descriptor
  814.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  815.  
  816.     srvDesc.Format = waterTex->GetDesc().Format;
  817.     md3dDevice->CreateShaderResourceView(waterTex.Get(), &srvDesc, hDescriptor);
  818.  
  819.     // next descriptor
  820.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  821.  
  822.     srvDesc.Format = fenceTex->GetDesc().Format;
  823.     md3dDevice->CreateShaderResourceView(fenceTex.Get(), &srvDesc, hDescriptor);
  824.  
  825.     auto srvCpuStart = mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
  826.     auto srvGpuStart = mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart();
  827.  
  828.     auto rtvCpuStart = mRtvHeap->GetCPUDescriptorHandleForHeapStart();
  829.  
  830.     mWaves->BuildDescriptors(
  831.         CD3DX12_CPU_DESCRIPTOR_HANDLE(srvCpuStart, waveSrvOffset, mCbvSrvDescriptorSize),
  832.         CD3DX12_GPU_DESCRIPTOR_HANDLE(srvGpuStart, waveSrvOffset, mCbvSrvDescriptorSize),
  833.         mCbvSrvDescriptorSize);
  834.  
  835.     mSobelFilter->BuildDescriptors(
  836.         CD3DX12_CPU_DESCRIPTOR_HANDLE(srvCpuStart, sobelSrvOffset, mCbvSrvDescriptorSize),
  837.         CD3DX12_GPU_DESCRIPTOR_HANDLE(srvGpuStart, sobelSrvOffset, mCbvSrvDescriptorSize),
  838.         mCbvSrvDescriptorSize);
  839.  
  840.     mOffscreenRT->BuildDescriptors(
  841.         CD3DX12_CPU_DESCRIPTOR_HANDLE(srvCpuStart, offscreenSrvOffset, mCbvSrvDescriptorSize),
  842.         CD3DX12_GPU_DESCRIPTOR_HANDLE(srvGpuStart, offscreenSrvOffset, mCbvSrvDescriptorSize),
  843.         CD3DX12_CPU_DESCRIPTOR_HANDLE(rtvCpuStart, rtvOffset, mRtvDescriptorSize));
  844. }
  845.  
  846. void SobelApp::BuildShadersAndInputLayout()
  847. {
  848.     const D3D_SHADER_MACRO defines[] =
  849.     {
  850.         "FOG", "1",
  851.         NULL, NULL
  852.     };
  853.  
  854.     const D3D_SHADER_MACRO alphaTestDefines[] =
  855.     {
  856.         "FOG", "1",
  857.         "ALPHA_TEST", "1",
  858.         NULL, NULL
  859.     };
  860.  
  861.     const D3D_SHADER_MACRO waveDefines[] =
  862.     {
  863.         "DISPLACEMENT_MAP", "1",
  864.         NULL, NULL
  865.     };
  866.  
  867.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_0");
  868.     mShaders["wavesVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", waveDefines, "VS", "vs_5_0");
  869.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", defines, "PS", "ps_5_0");
  870.     mShaders["alphaTestedPS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", alphaTestDefines, "PS", "ps_5_0");
  871.     mShaders["wavesUpdateCS"] = d3dUtil::CompileShader(L"Shaders\\WaveSim.hlsl", nullptr, "UpdateWavesCS", "cs_5_0");
  872.     mShaders["wavesDisturbCS"] = d3dUtil::CompileShader(L"Shaders\\WaveSim.hlsl", nullptr, "DisturbWavesCS", "cs_5_0");
  873.     mShaders["compositeVS"] = d3dUtil::CompileShader(L"Shaders\\Composite.hlsl", nullptr, "VS", "vs_5_0");
  874.     mShaders["compositePS"] = d3dUtil::CompileShader(L"Shaders\\Composite.hlsl", nullptr, "PS", "ps_5_0");
  875.     mShaders["sobelCS"] = d3dUtil::CompileShader(L"Shaders\\Sobel.hlsl", nullptr, "SobelCS", "cs_5_0");
  876.  
  877.  
  878.     mInputLayout =
  879.     {
  880.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  881.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  882.         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  883.     };
  884. }
  885.  
  886. void SobelApp::BuildLandGeometry()
  887. {
  888.     GeometryGenerator geoGen;
  889.     GeometryGenerator::MeshData grid = geoGen.CreateGrid(160.0f, 160.0f, 50, 50);
  890.  
  891.     //
  892.     // Extract the vertex elements we are interested and apply the height function to
  893.     // each vertex.  In addition, color the vertices based on their height so we have
  894.     // sandy looking beaches, grassy low hills, and snow mountain peaks.
  895.     //
  896.  
  897.     std::vector<Vertex> vertices(grid.Vertices.size());
  898.     for(size_t i = 0; i < grid.Vertices.size(); ++i)
  899.     {
  900.         auto& p = grid.Vertices[i].Position;
  901.         vertices[i].Pos = p;
  902.         vertices[i].Pos.y = GetHillsHeight(p.x, p.z);
  903.         vertices[i].Normal = GetHillsNormal(p.x, p.z);
  904.         vertices[i].TexC = grid.Vertices[i].TexC;
  905.     }
  906.  
  907.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  908.  
  909.     std::vector<std::uint16_t> indices = grid.GetIndices16();
  910.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  911.  
  912.     auto geo = std::make_unique<MeshGeometry>();
  913.     geo->Name = "landGeo";
  914.  
  915.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  916.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  917.  
  918.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  919.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  920.  
  921.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  922.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  923.  
  924.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  925.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  926.  
  927.     geo->VertexByteStride = sizeof(Vertex);
  928.     geo->VertexBufferByteSize = vbByteSize;
  929.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  930.     geo->IndexBufferByteSize = ibByteSize;
  931.  
  932.     SubmeshGeometry submesh;
  933.     submesh.IndexCount = (UINT)indices.size();
  934.     submesh.StartIndexLocation = 0;
  935.     submesh.BaseVertexLocation = 0;
  936.  
  937.     geo->DrawArgs["grid"] = submesh;
  938.  
  939.     mGeometries["landGeo"] = std::move(geo);
  940. }
  941.  
  942. void SobelApp::BuildWavesGeometry()
  943. {
  944.     GeometryGenerator geoGen;
  945.     GeometryGenerator::MeshData grid = geoGen.CreateGrid(160.0f, 160.0f, mWaves->RowCount(), mWaves->ColumnCount());
  946.  
  947.     std::vector<Vertex> vertices(grid.Vertices.size());
  948.     for(size_t i = 0; i < grid.Vertices.size(); ++i)
  949.     {
  950.         vertices[i].Pos = grid.Vertices[i].Position;
  951.         vertices[i].Normal = grid.Vertices[i].Normal;
  952.         vertices[i].TexC = grid.Vertices[i].TexC;
  953.     }
  954.  
  955.     std::vector<std::uint32_t> indices = grid.Indices32;
  956.  
  957.     UINT vbByteSize = mWaves->VertexCount()*sizeof(Vertex);
  958.     UINT ibByteSize = (UINT)indices.size()*sizeof(std::uint32_t);
  959.  
  960.     auto geo = std::make_unique<MeshGeometry>();
  961.     geo->Name = "waterGeo";
  962.  
  963.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  964.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  965.  
  966.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  967.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  968.  
  969.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  970.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  971.  
  972.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  973.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  974.  
  975.     geo->VertexByteStride = sizeof(Vertex);
  976.     geo->VertexBufferByteSize = vbByteSize;
  977.     geo->IndexFormat = DXGI_FORMAT_R32_UINT;
  978.     geo->IndexBufferByteSize = ibByteSize;
  979.  
  980.     SubmeshGeometry submesh;
  981.     submesh.IndexCount = (UINT)indices.size();
  982.     submesh.StartIndexLocation = 0;
  983.     submesh.BaseVertexLocation = 0;
  984.  
  985.     geo->DrawArgs["grid"] = submesh;
  986.  
  987.     mGeometries["waterGeo"] = std::move(geo);
  988. }
  989.  
  990. void SobelApp::BuildBoxGeometry()
  991. {
  992.     GeometryGenerator geoGen;
  993.     GeometryGenerator::MeshData box = geoGen.CreateBox(8.0f, 8.0f, 8.0f, 3);
  994.  
  995.     std::vector<Vertex> vertices(box.Vertices.size());
  996.     for (size_t i = 0; i < box.Vertices.size(); ++i)
  997.     {
  998.         auto& p = box.Vertices[i].Position;
  999.         vertices[i].Pos = p;
  1000.         vertices[i].Normal = box.Vertices[i].Normal;
  1001.         vertices[i].TexC = box.Vertices[i].TexC;
  1002.     }
  1003.  
  1004.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  1005.  
  1006.     std::vector<std::uint16_t> indices = box.GetIndices16();
  1007.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  1008.  
  1009.     auto geo = std::make_unique<MeshGeometry>();
  1010.     geo->Name = "boxGeo";
  1011.  
  1012.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  1013.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  1014.  
  1015.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  1016.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  1017.  
  1018.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  1019.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  1020.  
  1021.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  1022.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  1023.  
  1024.     geo->VertexByteStride = sizeof(Vertex);
  1025.     geo->VertexBufferByteSize = vbByteSize;
  1026.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  1027.     geo->IndexBufferByteSize = ibByteSize;
  1028.  
  1029.     SubmeshGeometry submesh;
  1030.     submesh.IndexCount = (UINT)indices.size();
  1031.     submesh.StartIndexLocation = 0;
  1032.     submesh.BaseVertexLocation = 0;
  1033.  
  1034.     geo->DrawArgs["box"] = submesh;
  1035.  
  1036.     mGeometries["boxGeo"] = std::move(geo);
  1037. }
  1038.  
  1039. void SobelApp::BuildPSOs()
  1040. {
  1041.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  1042.  
  1043.     //
  1044.     // PSO for opaque objects.
  1045.     //
  1046.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  1047.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  1048.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  1049.     opaquePsoDesc.VS = 
  1050.     { 
  1051.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  1052.         mShaders["standardVS"]->GetBufferSize()
  1053.     };
  1054.     opaquePsoDesc.PS = 
  1055.     { 
  1056.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  1057.         mShaders["opaquePS"]->GetBufferSize()
  1058.     };
  1059.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  1060.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  1061.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  1062.     opaquePsoDesc.SampleMask = UINT_MAX;
  1063.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  1064.     opaquePsoDesc.NumRenderTargets = 1;
  1065.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  1066.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  1067.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  1068.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  1069.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  1070.  
  1071.     //
  1072.     // PSO for transparent objects
  1073.     //
  1074.  
  1075.     D3D12_GRAPHICS_PIPELINE_STATE_DESC transparentPsoDesc = opaquePsoDesc;
  1076.  
  1077.     D3D12_RENDER_TARGET_BLEND_DESC transparencyBlendDesc;
  1078.     transparencyBlendDesc.BlendEnable = true;
  1079.     transparencyBlendDesc.LogicOpEnable = false;
  1080.     transparencyBlendDesc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
  1081.     transparencyBlendDesc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
  1082.     transparencyBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;
  1083.     transparencyBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;
  1084.     transparencyBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;
  1085.     transparencyBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
  1086.     transparencyBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
  1087.     transparencyBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
  1088.  
  1089.     transparentPsoDesc.BlendState.RenderTarget[0] = transparencyBlendDesc;
  1090.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&transparentPsoDesc, IID_PPV_ARGS(&mPSOs["transparent"])));
  1091.  
  1092.     //
  1093.     // PSO for alpha tested objects
  1094.     //
  1095.  
  1096.     D3D12_GRAPHICS_PIPELINE_STATE_DESC alphaTestedPsoDesc = opaquePsoDesc;
  1097.     alphaTestedPsoDesc.PS = 
  1098.     { 
  1099.         reinterpret_cast<BYTE*>(mShaders["alphaTestedPS"]->GetBufferPointer()),
  1100.         mShaders["alphaTestedPS"]->GetBufferSize()
  1101.     };
  1102.     alphaTestedPsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
  1103.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&alphaTestedPsoDesc, IID_PPV_ARGS(&mPSOs["alphaTested"])));
  1104.  
  1105.     //
  1106.     // PSO for drawing waves
  1107.     //
  1108.     D3D12_GRAPHICS_PIPELINE_STATE_DESC wavesRenderPSO = transparentPsoDesc;
  1109.     wavesRenderPSO.VS =
  1110.     {
  1111.         reinterpret_cast<BYTE*>(mShaders["wavesVS"]->GetBufferPointer()),
  1112.         mShaders["wavesVS"]->GetBufferSize()
  1113.     };
  1114.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&wavesRenderPSO, IID_PPV_ARGS(&mPSOs["wavesRender"])));
  1115.  
  1116.     //
  1117.     // PSO for compositing post process
  1118.     //
  1119.     D3D12_GRAPHICS_PIPELINE_STATE_DESC compositePSO = opaquePsoDesc;
  1120.     compositePSO.pRootSignature = mPostProcessRootSignature.Get();
  1121.  
  1122.     // Disable depth test.
  1123.     compositePSO.DepthStencilState.DepthEnable = false;
  1124.     compositePSO.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
  1125.     compositePSO.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
  1126.  
  1127.     compositePSO.VS =
  1128.     {
  1129.         reinterpret_cast<BYTE*>(mShaders["compositeVS"]->GetBufferPointer()),
  1130.         mShaders["compositeVS"]->GetBufferSize()
  1131.     };
  1132.     compositePSO.PS =
  1133.     {
  1134.         reinterpret_cast<BYTE*>(mShaders["compositePS"]->GetBufferPointer()),
  1135.         mShaders["compositePS"]->GetBufferSize()
  1136.     };
  1137.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&compositePSO, IID_PPV_ARGS(&mPSOs["composite"])));
  1138.  
  1139.     //
  1140.     // PSO for disturbing waves
  1141.     //
  1142.     D3D12_COMPUTE_PIPELINE_STATE_DESC wavesDisturbPSO = {};
  1143.     wavesDisturbPSO.pRootSignature = mWavesRootSignature.Get();
  1144.     wavesDisturbPSO.CS =
  1145.     {
  1146.         reinterpret_cast<BYTE*>(mShaders["wavesDisturbCS"]->GetBufferPointer()),
  1147.         mShaders["wavesDisturbCS"]->GetBufferSize()
  1148.     };
  1149.     wavesDisturbPSO.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
  1150.     ThrowIfFailed(md3dDevice->CreateComputePipelineState(&wavesDisturbPSO, IID_PPV_ARGS(&mPSOs["wavesDisturb"])));
  1151.  
  1152.     //
  1153.     // PSO for updating waves
  1154.     //
  1155.     D3D12_COMPUTE_PIPELINE_STATE_DESC wavesUpdatePSO = {};
  1156.     wavesUpdatePSO.pRootSignature = mWavesRootSignature.Get();
  1157.     wavesUpdatePSO.CS =
  1158.     {
  1159.         reinterpret_cast<BYTE*>(mShaders["wavesUpdateCS"]->GetBufferPointer()),
  1160.         mShaders["wavesUpdateCS"]->GetBufferSize()
  1161.     };
  1162.     wavesUpdatePSO.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
  1163.     ThrowIfFailed(md3dDevice->CreateComputePipelineState(&wavesUpdatePSO, IID_PPV_ARGS(&mPSOs["wavesUpdate"])));
  1164.  
  1165.     //
  1166.     // PSO for sobel
  1167.     //
  1168.     D3D12_COMPUTE_PIPELINE_STATE_DESC sobelPSO = {};
  1169.     sobelPSO.pRootSignature = mPostProcessRootSignature.Get();
  1170.     sobelPSO.CS =
  1171.     {
  1172.         reinterpret_cast<BYTE*>(mShaders["sobelCS"]->GetBufferPointer()),
  1173.         mShaders["sobelCS"]->GetBufferSize()
  1174.     };
  1175.     sobelPSO.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
  1176.     ThrowIfFailed(md3dDevice->CreateComputePipelineState(&sobelPSO, IID_PPV_ARGS(&mPSOs["sobel"])));
  1177. }
  1178.  
  1179. void SobelApp::BuildFrameResources()
  1180. {
  1181.     for(int i = 0; i < gNumFrameResources; ++i)
  1182.     {
  1183.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  1184.             1, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
  1185.     }
  1186. }
  1187.  
  1188. void SobelApp::BuildMaterials()
  1189. {
  1190.     auto grass = std::make_unique<Material>();
  1191.     grass->Name = "grass";
  1192.     grass->MatCBIndex = 0;
  1193.     grass->DiffuseSrvHeapIndex = 0;
  1194.     grass->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1195.     grass->FresnelR0 = XMFLOAT3(0.01f, 0.01f, 0.01f);
  1196.     grass->Roughness = 0.125f;
  1197.  
  1198.     // This is not a good water material definition, but we do not have all the rendering
  1199.     // tools we need (transparency, environment reflection), so we fake it for now.
  1200.     auto water = std::make_unique<Material>();
  1201.     water->Name = "water";
  1202.     water->MatCBIndex = 1;
  1203.     water->DiffuseSrvHeapIndex = 1;
  1204.     water->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 0.5f);
  1205.     water->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  1206.     water->Roughness = 0.0f;
  1207.  
  1208.     auto wirefence = std::make_unique<Material>();
  1209.     wirefence->Name = "wirefence";
  1210.     wirefence->MatCBIndex = 2;
  1211.     wirefence->DiffuseSrvHeapIndex = 2;
  1212.     wirefence->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  1213.     wirefence->FresnelR0 = XMFLOAT3(0.02f, 0.02f, 0.02f);
  1214.     wirefence->Roughness = 0.25f;
  1215.  
  1216.     mMaterials["grass"] = std::move(grass);
  1217.     mMaterials["water"] = std::move(water);
  1218.     mMaterials["wirefence"] = std::move(wirefence);
  1219. }
  1220.  
  1221. void SobelApp::BuildRenderItems()
  1222. {
  1223.     auto wavesRitem = std::make_unique<RenderItem>();
  1224.     wavesRitem->World = MathHelper::Identity4x4();
  1225.     XMStoreFloat4x4(&wavesRitem->TexTransform, XMMatrixScaling(5.0f, 5.0f, 1.0f));
  1226.     wavesRitem->DisplacementMapTexelSize.x = 1.0f / mWaves->ColumnCount();
  1227.     wavesRitem->DisplacementMapTexelSize.y = 1.0f / mWaves->RowCount();
  1228.     wavesRitem->GridSpatialStep = mWaves->SpatialStep();
  1229.     wavesRitem->ObjCBIndex = 0;
  1230.     wavesRitem->Mat = mMaterials["water"].get();
  1231.     wavesRitem->Geo = mGeometries["waterGeo"].get();
  1232.     wavesRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1233.     wavesRitem->IndexCount = wavesRitem->Geo->DrawArgs["grid"].IndexCount;
  1234.     wavesRitem->StartIndexLocation = wavesRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  1235.     wavesRitem->BaseVertexLocation = wavesRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  1236.  
  1237.     mRitemLayer[(int)RenderLayer::GpuWaves].push_back(wavesRitem.get());
  1238.  
  1239.     auto gridRitem = std::make_unique<RenderItem>();
  1240.     gridRitem->World = MathHelper::Identity4x4();
  1241.     XMStoreFloat4x4(&gridRitem->TexTransform, XMMatrixScaling(5.0f, 5.0f, 1.0f));
  1242.     gridRitem->ObjCBIndex = 1;
  1243.     gridRitem->Mat = mMaterials["grass"].get();
  1244.     gridRitem->Geo = mGeometries["landGeo"].get();
  1245.     gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1246.     gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
  1247.     gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  1248.     gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  1249.  
  1250.     mRitemLayer[(int)RenderLayer::Opaque].push_back(gridRitem.get());
  1251.  
  1252.     auto boxRitem = std::make_unique<RenderItem>();
  1253.     XMStoreFloat4x4(&boxRitem->World, XMMatrixTranslation(3.0f, 2.0f, -9.0f));
  1254.     boxRitem->ObjCBIndex = 2;
  1255.     boxRitem->Mat = mMaterials["wirefence"].get();
  1256.     boxRitem->Geo = mGeometries["boxGeo"].get();
  1257.     boxRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  1258.     boxRitem->IndexCount = boxRitem->Geo->DrawArgs["box"].IndexCount;
  1259.     boxRitem->StartIndexLocation = boxRitem->Geo->DrawArgs["box"].StartIndexLocation;
  1260.     boxRitem->BaseVertexLocation = boxRitem->Geo->DrawArgs["box"].BaseVertexLocation;
  1261.  
  1262.     mRitemLayer[(int)RenderLayer::AlphaTested].push_back(boxRitem.get());
  1263.  
  1264.     mAllRitems.push_back(std::move(wavesRitem));
  1265.     mAllRitems.push_back(std::move(gridRitem));
  1266.     mAllRitems.push_back(std::move(boxRitem));
  1267. }
  1268.  
  1269. void SobelApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  1270. {
  1271.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  1272.     UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
  1273.  
  1274.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  1275.     auto matCB = mCurrFrameResource->MaterialCB->Resource();
  1276.  
  1277.     // For each render item...
  1278.     for(size_t i = 0; i < ritems.size(); ++i)
  1279.     {
  1280.         auto ri = ritems[i];
  1281.  
  1282.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  1283.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  1284.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  1285.  
  1286.         CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  1287.         tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
  1288.  
  1289.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  1290.         D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
  1291.  
  1292.         cmdList->SetGraphicsRootDescriptorTable(0, tex);
  1293.         cmdList->SetGraphicsRootConstantBufferView(1, objCBAddress);
  1294.         cmdList->SetGraphicsRootConstantBufferView(3, matCBAddress);
  1295.  
  1296.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  1297.     }
  1298. }
  1299.  
  1300. void SobelApp::DrawFullscreenQuad(ID3D12GraphicsCommandList* cmdList)
  1301. {
  1302.     // Null-out IA stage since we build the vertex off the SV_VertexID in the shader.
  1303.     cmdList->IASetVertexBuffers(0, 1, nullptr);
  1304.     cmdList->IASetIndexBuffer(nullptr);
  1305.     cmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  1306.  
  1307.     cmdList->DrawInstanced(6, 1, 0, 0);
  1308. }
  1309.  
  1310. std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> SobelApp::GetStaticSamplers()
  1311. {
  1312.     // Applications usually only need a handful of samplers.  So just define them all up front
  1313.     // and keep them available as part of the root signature.  
  1314.  
  1315.     const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
  1316.         0, // shaderRegister
  1317.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1318.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1319.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1320.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1321.  
  1322.     const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
  1323.         1, // shaderRegister
  1324.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  1325.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1326.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1327.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1328.  
  1329.     const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
  1330.         2, // shaderRegister
  1331.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1332.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1333.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1334.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  1335.  
  1336.     const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
  1337.         3, // shaderRegister
  1338.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  1339.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1340.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1341.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  1342.  
  1343.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
  1344.         4, // shaderRegister
  1345.         D3D12_FILTER_ANISOTROPIC, // filter
  1346.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1347.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1348.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
  1349.         0.0f,                             // mipLODBias
  1350.         8);                               // maxAnisotropy
  1351.  
  1352.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
  1353.         5, // shaderRegister
  1354.         D3D12_FILTER_ANISOTROPIC, // filter
  1355.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1356.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1357.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
  1358.         0.0f,                              // mipLODBias
  1359.         8);                                // maxAnisotropy
  1360.  
  1361.     return { 
  1362.         pointWrap, pointClamp,
  1363.         linearWrap, linearClamp, 
  1364.         anisotropicWrap, anisotropicClamp };
  1365. }
  1366.  
  1367. float SobelApp::GetHillsHeight(float x, float z)const
  1368. {
  1369.     return 0.3f*(z*sinf(0.1f*x) + x*cosf(0.1f*z));
  1370. }
  1371.  
  1372. XMFLOAT3 SobelApp::GetHillsNormal(float x, float z)const
  1373. {
  1374.     // n = (-df/dx, 1, -df/dz)
  1375.     XMFLOAT3 n(
  1376.         -0.03f*z*cosf(0.1f*x) - 0.3f*cosf(0.1f*z),
  1377.         1.0f,
  1378.         -0.3f*sinf(0.1f*x) + 0.03f*x*sinf(0.1f*z));
  1379.  
  1380.     XMVECTOR unitNormal = XMVector3Normalize(XMLoadFloat3(&n));
  1381.     XMStoreFloat3(&n, unitNormal);
  1382.  
  1383.     return n;
  1384. }
  1385.